package com.fastloan.safe.mgt.root.service.impl;

import com.fastloan.safe.core.util.ManagerKit;
import com.fastloan.safe.mgt.auth.model.CmuRoleFun;
import com.fastloan.safe.mgt.auth.model.CmuUserFun;
import com.fastloan.safe.mgt.auth.service.CmuRoleFunService;
import com.fastloan.safe.mgt.auth.service.CmuUserFunService;
import com.fastloan.safe.mgt.root.dao.CmDefFunMapper;
import com.fastloan.safe.mgt.root.model.CmDefFun;
import com.fastloan.safe.mgt.root.model.CmDefFunRes;
import com.fastloan.safe.mgt.root.model.CmDefRoleFun;
import com.fastloan.safe.mgt.root.model.CmuFun;
import com.fastloan.safe.mgt.root.model.vo.DefFunTreeVo;
import com.fastloan.safe.mgt.root.model.vo.DefFunVo;
import com.fastloan.safe.mgt.root.service.CmDefFunResService;
import com.fastloan.safe.mgt.root.service.CmDefFunService;
import com.fastloan.safe.mgt.root.service.CmDefRoleFunService;
import com.fastloan.safe.mgt.root.service.CmFunService;
import com.kawins.base.BaseMapper;
import com.kawins.base.baseabs.BaseServiceImpl;
import com.kawins.supers.table.manager.DataTable;
import com.kawins.supers.tree.Bean2TreeUtil;
import com.kawins.util.colle.ListSortUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

@Service
public class CmDefFunServiceImpl extends BaseServiceImpl<CmDefFun> implements CmDefFunService {

    @Autowired
    private CmDefFunMapper defFunMapper;

    @Autowired
    private CmDefFunResService defFunResService;

    @Autowired
    private CmDefRoleFunService defRoleFunService;

    @Autowired
    private CmFunService funService;

    @Autowired
    private CmuUserFunService userFunService;

    @Autowired
    private CmuRoleFunService roleFunService;

    @Override
    protected BaseMapper<CmDefFun> buildDao() {
        return defFunMapper;
    }

    @Override
    @DataTable(name = "defFunPageList")
    public List<DefFunVo> pageList(Map<String, Object> map) {
        return defFunMapper.pageList(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertForShort(CmDefFun cmDefFun, String[] apiIds, String[] menuIds) {
        log.debug("增加功能:" + cmDefFun);
        cmDefFun.setCreateBy(ManagerKit.getUser().getId());
        cmDefFun.setCreateTime(new Date());
        if (StringUtils.isBlank(cmDefFun.getRelyOnId())) {
            cmDefFun.setRelyOnId(null);
        }
        if (StringUtils.isNotBlank(cmDefFun.getParentId())) {
            CmDefFun defFun = selectByPrimaryKey(cmDefFun.getParentId());
            cmDefFun.setIsAdmin(defFun.getIsAdmin());
        } else {
            cmDefFun.setParentId(TOP_FUN_PARENT_ID);
            if (cmDefFun.getIsAdmin().equals(1)) {
                cmDefFun.setIsDef(null);
            }
        }
        updateSortBatch(cmDefFun.getShorts(), cmDefFun.getParentId(), null, false);
        insertSelective(cmDefFun);
        bachInsertFunRes(cmDefFun.getId(), apiIds, menuIds);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateForShort(CmDefFun cmDefFun, String[] apiIds, String[] menuIds) {
        log.debug("更新功能:" + cmDefFun);
        cmDefFun.setCreateBy(null);
        cmDefFun.setCreateTime(null);
        cmDefFun.setParentId(null);
        CmDefFun oldDefFun = selectByPrimaryKey(cmDefFun.getId());
        //更新排序
        if (!oldDefFun.getShorts().equals(cmDefFun.getShorts())) {
            updateSortBatch(cmDefFun.getShorts(), oldDefFun.getParentId(), oldDefFun.getShorts(), false);
            updateByPrimaryKeySelective(new CmDefFun().setId(oldDefFun.getId()).setShorts(cmDefFun.getShorts()));
        } else {
            cmDefFun.setShorts(null);
            updateByPrimaryKeySelective(cmDefFun);
            defFunResService.delete(new CmDefFunRes().setFunId(cmDefFun.getId()));
            bachInsertFunRes(cmDefFun.getId(), apiIds, menuIds);
        }
    }

    @Override
    public List<DefFunTreeVo> selectAll2Tree(boolean isAdmin) {
        List<DefFunTreeVo> defFunTreeVos = defFunMapper.select2FunBaseVo(isAdmin);
        return buildDefFunTree(defFunTreeVos);
    }


    @Override
    public List<DefFunTreeVo> selectAll2TreeCheck(String defRoleId, boolean isAdmin) {
        List<DefFunTreeVo> defFunTreeVos = defFunMapper.select2FunBaseVo(isAdmin);
        List<CmDefRoleFun> defRoleFunList = defRoleFunService.select(new CmDefRoleFun().setDefRoleId(defRoleId));
        for (DefFunTreeVo defFunTreeVo : defFunTreeVos) {
            for (CmDefRoleFun defRoleFun : defRoleFunList) {
                if (defFunTreeVo.getId().equals(defRoleFun.getDefFunId())) {
                    defFunTreeVo.setCheck(true);
                }
            }
        }
        return buildDefFunTree(defFunTreeVos);
    }

    @Override
    public List<DefFunTreeVo> selectAllSonByTop(String funId, boolean hasSelf) {
        return defFunMapper.selectAllSonByTop(funId, hasSelf);
    }

    @Override
    public List<CmDefFun> selectByUserId(String userId) {
        List<CmDefRoleFun> defFunsByUserRole = defRoleFunService.selectByUserId(userId);
        List<CmuUserFun> defFunsByUserFun = userFunService.select(new CmuUserFun().setUserId(userId).setIsAdd(1));
        List<CmuUserFun> defFunsByUserFunNoHas = userFunService.select(new CmuUserFun().setUserId(userId).setIsAdd(0));
        HashSet<String> defFunsByUserRoleSet = new HashSet<>(defFunsByUserRole.size());
        for (CmDefRoleFun defRoleFun : defFunsByUserRole) {
            defFunsByUserRoleSet.add(defRoleFun.getDefFunId());
        }
        HashSet<String> defFunsByUserFunSet = new HashSet<>(defFunsByUserFun.size());
        for (CmuUserFun cmuUserFun : defFunsByUserFun) {
            defFunsByUserFunSet.add(cmuUserFun.getDefFunId());
        }
        HashSet<String> defFunsByUserFunNoHasSet = new HashSet<>(defFunsByUserFunNoHas.size());
        for (CmuUserFun cmuUserFun : defFunsByUserFun) {
            defFunsByUserFunSet.add(cmuUserFun.getDefFunId());
        }
        defFunsByUserRoleSet.addAll(defFunsByUserFunSet);
        defFunsByUserRoleSet.removeAll(defFunsByUserFunNoHasSet);
        Example example = new Example(CmDefFun.class);
        example.createCriteria().andIn("id", defFunsByUserRoleSet);
        return selectByExample(example);
    }

    @Override
    public List<CmDefFun> selectTopByOrg(String orgId) {
        return defFunMapper.selectTopByOrg(orgId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(String cmDefFunId) {
        deleteByPrimaryKey(cmDefFunId);
        defFunResService.delete(new CmDefFunRes().setFunId(cmDefFunId));
        defRoleFunService.delete(new CmDefRoleFun().setDefFunId(cmDefFunId));
        roleFunService.delete(new CmuRoleFun().setDefFunId(cmDefFunId));
        userFunService.delete(new CmuUserFun().setDefFunId(cmDefFunId));
        CmDefFun defFun = selectByPrimaryKey(cmDefFunId);
        if (TOP_FUN_PARENT_ID.equals(defFun.getParentId())) {
            funService.delete(new CmuFun().setDefFunId(cmDefFunId));
        }
    }

    private void updateSortBatch(Integer shorts, String parentId, Integer oldSorts, boolean isDel) {
        Example example = new Example(CmDefFun.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("parentId", parentId);
        int impairment = 1;
        impairment = getImpairment(shorts, oldSorts, isDel, criteria, impairment);
        List<CmDefFun> defFunList = selectByExample(example);
        if (defFunList.size() != 0) {
            for (CmDefFun defFun : defFunList) {
                defFun.setShorts(defFun.getShorts() + impairment);
                updateByPrimaryKeySelective(defFun);
            }
        }
    }

    private int getImpairment(Integer shorts, Integer oldSorts, boolean isDel, Example.Criteria criteria, int impairment) {
        if (oldSorts == null) {
            if (isDel) {
                impairment = -1;
            }
            criteria.andGreaterThanOrEqualTo("shorts", shorts);
        } else {
            if (shorts > oldSorts) {
                criteria.andBetween("shorts", oldSorts + 1, shorts);
                impairment = -1;
            } else {
                criteria.andBetween("shorts", shorts, oldSorts - 1);
            }
        }
        return impairment;
    }

    private void bachInsertFunRes(String defFunId, String[] apiIds, String[] menuIds) {
        List<CmDefFunRes> defFunResList = new ArrayList<>();
        if (apiIds != null && apiIds.length > 0) {
            Set<String> set = new HashSet<>();
            for (String apiId : apiIds) {
                set.add(apiId);
            }
            for (String resApiId : set) {
                defFunResList.add(new CmDefFunRes().setResType(0).setFunId(defFunId)
                        .setResId(resApiId));
            }
        }
        if (menuIds != null && menuIds.length > 0) {
            Set<String> set = new HashSet<>();
            for (String menuId : menuIds) {
                set.add(menuId);
            }
            for (String menuId : set) {
                defFunResList.add(new CmDefFunRes().setResType(1).setFunId(defFunId)
                        .setResId(menuId));
            }
        }
        if (CollectionUtils.isNotEmpty(defFunResList)) {
            defFunResService.insertList(defFunResList);
        }
    }

    private List<DefFunTreeVo> buildDefFunTree(List<DefFunTreeVo> defFunTreeVos) {
        LinkedHashMap<String, Integer> orderMap = new LinkedHashMap<>();
        orderMap.put("shorts", ListSortUtil.ASC);
        Bean2TreeUtil<DefFunTreeVo> bean2TreeUtil = new Bean2TreeUtil<>(orderMap);
        return bean2TreeUtil.getChildNodesByParentId(defFunTreeVos, TOP_FUN_PARENT_ID);
    }
}
